package xmlproject;

import gui.MainWindow;
import java.util.Scanner;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.xml.sax.SAXException;

import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.Difference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

/**
 *
 * @author Jano
 */
public class XMLUtils {

    /**
     * Creates a document.
     *
     * @returns doc new instance of DOM Document object
     * @throws ParserConfigurationException
     */
    public static Document createDoc() throws ParserConfigurationException {

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        Document doc = docBuilder.newDocument();
        return doc;
    }

    /**
     * Checks if directory exist
     *
     * @param dir file instance from given path
     *
     * @returns doc attribute of Document
     */
    public static Boolean checkIfDirecoryExist(File dir) {

        if (dir.exists()) {
            return Boolean.TRUE;
        } else {
            return Boolean.FALSE;
        }
    }

    /**
     * Checks if file is .xml
     *
     * @param file file to check
     *
     * @returns true - file is .xml or false file is not .xml
     */
    public static boolean isXML(File file) {

        String suffix = file.getName();
        int i = suffix.lastIndexOf('.');

        if (i > 0 && i < suffix.length() - 1) {
            suffix = suffix.substring(i + 1).toLowerCase();
            if (suffix.compareTo("xml") == 0) {
                return true;
            }
            return false;
        }
        return false;
    }

    /**
     * Gets path attribute from root element of given xml file
     *
     * @param file xml file
     *
     * @returns path
     */
    public static String getPathFromXMLToAnalyze(File file) throws ParserConfigurationException, SAXException, IOException {

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        Document doc = docBuilder.parse(file);
        Element documentElement = doc.getDocumentElement();
        String path = documentElement.getAttribute("path");
        return path;
    }

    /**
     * Creates a root element with attributes path, countOfFiles and size
     *
     * @param doc instance of DOM Document object
     * @param path a path from standart input to evaluate
     * @param dir file instance from given path to evaluate
     *
     * @returns rootElement a root element of document
     */
    public static Element createRootElement(Document doc, String path, File dir) {

        Element rootElement = doc.createElement("Directory");
        doc.appendChild(rootElement);
        rootElement.setAttribute("path", path);
        rootElement.setAttribute("numberOfFiles", String.valueOf(dir.listFiles().length));

        FileAndDirectorySizeUtils.getDirectorySize(dir.listFiles());
        Long directorySize = FileAndDirectorySizeUtils.getAttributeSize();
        rootElement.setAttribute("size", FileAndDirectorySizeUtils.getSize(directorySize));
        FileAndDirectorySizeUtils.setAttributeSize(0l);

        return rootElement;
    }

    /**
     * Gets through a file system from given path and builds a tree responsive
     * to a structure of data on hard disk, creates 2 types of elements, element
     * 'Directory' for directory and 'File' for file, both with attributes size,
     * countOfFiles and name.
     *
     * @param files an array of childs of a given directory
     * @param rootElement root element of document
     * @param doc instance of DOM Document object
     *
     * @returns rootElement a root element of document
     */
    public static void getFilesInDir(File[] files, Element rootElement, Document doc) {

        for (File child : files) {
            if (child.isDirectory()) {
                if (Files.isExecutable(child.toPath()) && Files.isReadable(child.toPath())) {
              /*  try {
                    child.listFiles();
                }
                catch (NullPointerException ex)
                {
                    continue;
                }*/
                    FileAndDirectorySizeUtils.setAttributeSize(0l);

                    Element directoryElement = doc.createElement("Directory");
                    directoryElement.setAttribute("name", child.getName());
                    
                    
                    directoryElement.setAttribute("numberOfFiles", String.valueOf(child.listFiles().length));

                    FileAndDirectorySizeUtils.getDirectorySize(child.listFiles());
                    
                    Long directorySize = FileAndDirectorySizeUtils.getAttributeSize();
                    directoryElement.setAttribute("size", FileAndDirectorySizeUtils.getSize(directorySize));
                    FileAndDirectorySizeUtils.setAttributeSize(0l);

                    rootElement.appendChild(directoryElement);

                    getFilesInDir(child.listFiles(), directoryElement, doc);
               }
            } else {
                /*
                try {
                    FileAndDirectorySizeUtils.getSize(child);
                }
                catch (NullPointerException ex)
                {
                    continue;
                }*/
                if (Files.isExecutable(child.toPath()) && Files.isReadable(child.toPath())) {
                    Element fileElement = doc.createElement("File");
                    fileElement.setAttribute("name", child.getName());
                    fileElement.setAttribute("size", FileAndDirectorySizeUtils.getSize(child));
                    rootElement.appendChild(fileElement);
                }
            }
        }
    }

    /**
     * Creates and saves XML document.
     *
     * @param doc instance of DOM Document object
     * @throws TransformerConfigurationException
     * @throws TransformerException
     */
    public static void saveXML(Document doc, String pathToSaveFile, String outputFileName) throws TransformerConfigurationException, TransformerException {

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(new File(pathToSaveFile + "\\" + outputFileName + ".xml"));
        transformer.transform(source, result);
    }
}
